﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;

namespace HYPreviewer
{
	public class LegendCommon
	{
		public static Legend GetFamily2DImg(UIApplication uiApp, Autodesk.Revit.DB.Document sourceDocument)
		{
			Legend result;
			try
			{
				Legend legend = new Legend();
				List<CurveInfo> list = new List<CurveInfo>();
				Autodesk.Revit.DB.View referenceView = LegendCommon.GetReferenceView(sourceDocument);
				if (referenceView == null)
				{
					result = null;
				}
				else
				{
					List<Element> list2 = new List<Element>();
					List<Element> list3 = new List<Element>();
					List<Element> list4 = new List<Element>();
					List<Element> list5 = new List<Element>();
					List<Element> list6 = new FilteredElementCollector(sourceDocument).OfClass(typeof(CurveElement)).ToElements().ToList<Element>();
					list4 = new FilteredElementCollector(sourceDocument).OfClass(typeof(TextElement)).ToElements().ToList<Element>();
					List<Element> list7 = new FilteredElementCollector(sourceDocument).OfClass(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_GenericAnnotation).ToElements().ToList<Element>();
					if (list7 != null)
					{
						foreach (Element item in list7)
						{
							list4.Add(item);
						}
					}
					list3 = new FilteredElementCollector(sourceDocument).OfClass(typeof(FilledRegion)).ToElements().ToList<Element>();
					foreach (Element element in list6)
					{
						if (element is SymbolicCurve)
						{
							list2.Add(element);
						}
						else if (element is FilledRegion)
						{
							list3.Add(element);
						}
						else if (element is DetailCurve)
						{
							list2.Add(element);
						}
						else if (element is AnnotationSymbol)
						{
							list4.Add(element);
						}
						else if (element is TextElement)
						{
							list4.Add(element);
						}
						else if (element is FamilyInstance)
						{
							list5.Add(element);
						}
					}
					foreach (Element element2 in list2)
					{
						try
						{
							int num = element2.get_Parameter(BuiltInParameter.CURVE_VISIBILITY_PARAM).AsInteger();
							if (LegendCommon.IsSymbolicCurveCoarse(num) && num != -1)
							{
								Curve curve = (element2.Location as LocationCurve).Curve;
								if (curve.IsBound || curve.IsCyclic)
								{
									if (curve is Arc && Math.Abs(curve.Length - Math.PI * (curve as Arc).Radius * 2.0) < 1E-06)
									{
										XYZ center = (curve as Arc).Center;
										double radius = (curve as Arc).Radius;
										Arc curve2 = Arc.Create(center, radius, 0.0, Math.PI, XYZ.BasisX, XYZ.BasisY);
										Arc curve3 = Arc.Create(center, radius, Math.PI, Math.PI*2, XYZ.BasisX, XYZ.BasisY);
										list.Add(new CurveInfo(curve2, PenColor.PC_Black, 1f));
										list.Add(new CurveInfo(curve3, PenColor.PC_Black, 1f));
									}
									else
									{
										list.Add(new CurveInfo(curve, PenColor.PC_Black, 1f));
									}
								}
							}
						}
						catch (Exception)
						{
						}
					}
					List<FillRegion> list8 = new List<FillRegion>();
					foreach (Element element3 in list3)
					{
						FilledRegion filledRegion = element3 as FilledRegion;
						if (filledRegion != null)
						{
							List<CurveLoop> list9 = new List<CurveLoop>();
							list9 = filledRegion.GetBoundaries().ToList<CurveLoop>();
							bool flag = false;
							List<Curve> list10 = new List<Curve>();
							if (list9.Count == 2)
							{
								foreach (CurveLoop source in list9)
								{
									foreach (Curve item2 in source.ToList<Curve>())
									{
										list10.Add(item2);
									}
								}
								if (list10.Count == 0)
								{
									continue;
								}
								flag = true;
								XYZ center2 = (list10[0] as Arc).Center;
								for (int i = 1; i < list10.Count; i++)
								{
									Arc arc = list10[i] as Arc;
									if (center2.DistanceTo(arc.Center) > 1E-06)
									{
										flag = false;
										break;
									}
								}
							}
							if (flag)
							{
								FillRegion item3 = new FillRegion(list10, PenColor.PC_Black);
								list8.Add(item3);
							}
							else
							{
								foreach (CurveLoop source2 in list9)
								{
									bool flag2 = false;
									foreach (Curve curve4 in source2.ToList<Curve>())
									{
										if (curve4 is Arc && (curve4 as Arc).Normal.IsAlmostEqualTo(-XYZ.BasisZ))
										{
											flag2 = true;
											break;
										}
									}
									list10 = new List<Curve>();
									if (flag2)
									{
										for (int j = source2.Count<Curve>() - 1; j >= 0; j--)
										{
											Curve curve5 = source2.ElementAt(j);
											XYZ endPoint = curve5.GetEndPoint(1);
											XYZ endPoint2 = curve5.GetEndPoint(0);
											if (curve5 is Arc)
											{
												Arc arc2 = curve5 as Arc;
												double num2 = Math.PI*2 - XYZ.BasisX.AngleTo(endPoint - arc2.Center);
												double num3 = Math.PI*2 - XYZ.BasisX.AngleTo(endPoint2 - arc2.Center);
												if (Math.Abs(num2) < 1E-05 || Math.Abs(num2 - Math.PI*2) < 1E-05)
												{
													num2 = 0.0;
												}
												Arc item4 = Arc.Create(arc2.Center, arc2.Radius, num2, num3, XYZ.BasisX, XYZ.BasisY);
												list10.Add(item4);
											}
											else if (curve5 is Line)
											{
												list10.Add(Line.CreateBound(endPoint, endPoint2));
											}
										}
									}
									else
									{
										foreach (Curve item5 in source2.ToList<Curve>())
										{
											list10.Add(item5);
										}
									}
									FillRegion item6 = new FillRegion(list10, PenColor.PC_Black);
									list8.Add(item6);
								}
							}
						}
					}
					legend.FillRegions = list8;
					List<TextNoteInfo> list11 = new List<TextNoteInfo>();
					foreach (Element element4 in list4)
					{
						TextElement textElement = element4 as TextElement;
						if (textElement != null)
						{
							list11.Add(LegendCommon.CreateTextNote(textElement));
						}
						else
						{
							AnnotationSymbol annotationSymbol = element4 as AnnotationSymbol;
							if (annotationSymbol != null)
							{
								XYZ point = (annotationSymbol.Location as LocationPoint).Point;
								Document document = sourceDocument.EditFamily(annotationSymbol.Symbol.Family);
								if (document != null)
								{
									List<Element> list12 = new FilteredElementCollector(document).OfClass(typeof(TextElement)).ToElements().ToList<Element>();
									if (list12.Count != 0)
									{
										textElement = (list12[0] as TextElement);
										TextNoteInfo item7 = LegendCommon.CreateTextNote(textElement);
										item7.m_Position = point;
										list11.Add(item7);
									}
								}
							}
						}
					}
					legend.Texts = list11;
					Options options = new Options();
					options.View = uiApp.ActiveUIDocument.ActiveView;
					options.ComputeReferences = true;
					if (list.Count == 0)
					{
						foreach (Element element5 in list5)
						{
							bool flag3 = false;
							if (element5.Category.Id.IntegerValue == -2002000)
							{
								int num4 = element5.get_Parameter(BuiltInParameter.CURVE_VISIBILITY_PARAM).AsInteger();
								if (LegendCommon.IsSymbolicCurveCoarse(num4) && num4 != -1)
								{
									flag3 = true;
								}
							}
							else if (element5.Category.Id.IntegerValue == -2000150)
							{
								int num5 = element5.get_Parameter(BuiltInParameter.GEOM_VISIBILITY_PARAM).AsInteger();
								if (24576 == num5 && num5 != -1)
								{
									flag3 = true;
								}
							}
							else
							{
								int num6 = element5.get_Parameter(BuiltInParameter.GEOM_VISIBILITY_PARAM).AsInteger();
								if (LegendCommon.IsCoarse(num6) && num6 != -1)
								{
									flag3 = true;
								}
							}
							if (flag3)
							{
								List<GeometryObject> list13 = new List<GeometryObject>();
								FamilySymbol symbol = (element5 as FamilyInstance).Symbol;
								foreach (GeometryObject item8 in (element5 as FamilyInstance).Symbol.get_Geometry(options))
								{
									list13.Add(item8);
								}
								foreach (GeometryObject geometryObject in list13)
								{
									if (geometryObject is Arc || geometryObject is Line)
									{
										Curve curve6 = (Curve)geometryObject;
										if (curve6.IsBound)
										{
											list.Add(new CurveInfo(curve6, PenColor.PC_Black, 1f));
										}
										if (geometryObject is Arc && Math.Abs(curve6.Length - Math.PI * (curve6 as Arc).Radius * 2.0) < 1E-06)
										{
											XYZ center3 = (curve6 as Arc).Center;
											double radius2 = (curve6 as Arc).Radius;
											Arc curve7 = Arc.Create(center3, radius2, 0.0, Math.PI, XYZ.BasisX, XYZ.BasisY);
											Arc curve8 = Arc.Create(center3, radius2, Math.PI, Math.PI*2, XYZ.BasisX, XYZ.BasisY);
											list.Add(new CurveInfo(curve7, PenColor.PC_Black, 1f));
											list.Add(new CurveInfo(curve8, PenColor.PC_Black, 1f));
										}
									}
									else if (geometryObject is Solid)
									{
										Solid solid = geometryObject as Solid;
										if (!(solid == null))
										{
											foreach (object obj in solid.Edges)
											{
												Curve curve6 = ((Edge)obj).AsCurve();
												if (curve6.IsBound)
												{
													list.Add(new CurveInfo(curve6, PenColor.PC_Black, 1f));
												}
											}
										}
									}
								}
							}
						}
					}
					if (list.Count == 0)
					{
						LegendCommon.DeviceExtension(sourceDocument, referenceView, options, ref list);
					}
					legend.Curves = list;
					if (list.Count == 0)
					{
						result = null;
					}
					else
					{
						result = legend;
					}
				}
			}
			catch (Exception)
			{
				result = null;
			}
			return result;
		}

		public static TextNoteInfo CreateTextNote(TextElement text)
		{
			XYZ coord = text.Coord;
			string text2 = text.Text;
			TextNoteInfo.AlignVType alignVType = TextNoteInfo.AlignVType.AVT_Middle;
			if ((int)text.VerticalAlignment == 2)
			{
				alignVType = TextNoteInfo.AlignVType.AVT_Middle;
			}
			else if ((int)text.VerticalAlignment == 1)
			{
				alignVType = TextNoteInfo.AlignVType.AVT_Bottom;
			}
			else if (text.VerticalAlignment == null)
			{
				alignVType = TextNoteInfo.AlignVType.AVT_Top;
			}
			TextNoteInfo.AlignHType alignHType = TextNoteInfo.AlignHType.AHT_Center;
			if ((int)text.HorizontalAlignment == 2)
			{
				alignHType = TextNoteInfo.AlignHType.AHT_Center;
			}
			else if (text.HorizontalAlignment == null)
			{
				alignHType = TextNoteInfo.AlignHType.AHT_Left;
			}
			else if ((int)text.HorizontalAlignment == 1)
			{
				alignHType = TextNoteInfo.AlignHType.AHT_Right;
			}
			double boundingBoxWidth = text.Height * 0.7 * (double)text2.Length;
			return new TextNoteInfo(text2, PenColor.PC_Black, text.Height * 0.7, coord, alignHType, alignVType, boundingBoxWidth, text.Height);
		}

		public static Autodesk.Revit.DB.View GetReferenceView(Autodesk.Revit.DB.Document sourceDocument)
		{
			FilteredElementIterator elementIterator = new FilteredElementCollector(sourceDocument).OfClass(typeof(Autodesk.Revit.DB.View)).GetElementIterator();
			elementIterator.Reset();
			Autodesk.Revit.DB.View view = null;
			while (elementIterator.MoveNext())
			{
				Element element = elementIterator.Current;
				Autodesk.Revit.DB.View view2 = element as Autodesk.Revit.DB.View;
				if (view2 != null && !view2.IsTemplate && (int)view2.ViewType == 1)
				{
					view = view2;
					break;
				}
			}
			if (view == null)
			{
				elementIterator.Reset();
				while (elementIterator.MoveNext())
				{
					Element element2 = elementIterator.Current;
					Autodesk.Revit.DB.View view3 = element2 as Autodesk.Revit.DB.View;
					if (view3 != null && !view3.IsTemplate && (int)view3.ViewType == 2)
					{
						view = view3;
						break;
					}
				}
			}
			if (view == null)
			{
				elementIterator.Reset();
				while (elementIterator.MoveNext())
				{
					Element element3 = elementIterator.Current;
					Autodesk.Revit.DB.View view4 = element3 as Autodesk.Revit.DB.View;
					if (view4 != null && !view4.IsTemplate && (int)view4.ViewType == 7)
					{
						view = view4;
						break;
					}
				}
			}
			return view;
		}

		private static void DeviceExtension(Autodesk.Revit.DB.Document sourceDocument, Autodesk.Revit.DB.View view, Options options, ref List<CurveInfo> curves)
		{
			List<Element> list = new List<Element>();
			foreach (Element element in new FilteredElementCollector(sourceDocument, view.Id).ToElements())
			{
				if (element is Extrusion)
				{
					list.Add(element);
				}
			}
			foreach (Element element2 in list)
			{
				GeometryElement geometryElement = element2.get_Geometry(options);
				List<GeometryObject> list2 = new List<GeometryObject>();
				foreach (GeometryObject item in geometryElement)
				{
					list2.Add(item);
				}
				foreach (GeometryObject geometryObject in list2)
				{
					if (geometryObject is Solid)
					{
						foreach (object obj in (geometryObject as Solid).Faces)
						{
							PlanarFace planarFace = ((Face)obj) as PlanarFace;
							if (planarFace != null && planarFace.FaceNormal().IsAlmostEqualTo(XYZ.BasisZ))
							{
								foreach (object obj2 in planarFace.EdgeLoops)
								{
									foreach (object obj3 in ((EdgeArray)obj2))
									{
										Curve curve = ((Edge)obj3).AsCurve();
										if (Geometry.IsEqual(curve.GetEndPoint(0).Z, curve.GetEndPoint(1).Z) && curve.IsBound)
										{
											curves.Add(new CurveInfo(curve, PenColor.PC_Black, 1f));
										}
									}
								}
							}
						}
					}
				}
			}
		}

		private static bool IsCoarse(int value)
		{
			return (value & 8206) == 8206;
		}

		private static bool IsSymbolicCurveCoarse(int value)
		{
			return (value & 8192) == 8192;
		}
	}
}
